/*
 MDAL - Mesh Data Abstraction Library (MIT License)
 Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
*/
#include "gtest/gtest.h"
#include <string>
#include <vector>
#include <cmath>

//mdal
#include "mdal.h"
#include "mdal_testutils.hpp"
#include "mdal_utils.hpp"

TEST( MeshFlo2dTest, missing_required_file )
{
  std::string path = test_file( "/flo2d/missing_required_file/BASE.OUT" );
  EXPECT_TRUE( std::string( MDAL_MeshNames( path.c_str() ) ).empty() );
  MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
  ASSERT_EQ( m, nullptr );
  MDAL_Status s = MDAL_LastStatus();
  EXPECT_EQ( MDAL_Status::Err_UnknownFormat, s );
}

TEST( MeshFlo2dTest, WriteBarnHDF5_New )
{
  std::string path = test_file( "/flo2d/BarnHDF5/TIMDEP.HDF5" );
  std::string newFile = tmp_file( "/flow2d_BarnHDF5_New.hdf5" );

  // cleanup from previous run
  deleteFile( newFile );

  // FLO-2D is only on face datasets
  size_t f_count = 521;
  std::vector<double> valsScalar( f_count, 1.1 );
  std::vector<double> valsVector( 2 * f_count, 2.2 );

  // Create a new dat file
  {
    EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh2d" );
    MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
    ASSERT_NE( m, nullptr );
    MDAL_DriverH driver = MDAL_driverFromName( "FLO2D" );
    ASSERT_NE( driver, nullptr );
    ASSERT_TRUE( MDAL_DR_writeDatasetsCapability( driver, MDAL_DataLocation::DataOnFaces ) );
    ASSERT_FALSE( MDAL_DR_writeDatasetsCapability( driver, MDAL_DataLocation::DataOnVertices ) );
    ASSERT_FALSE( MDAL_DR_writeDatasetsCapability( driver, MDAL_DataLocation::DataOnVolumes ) );

    ASSERT_EQ( 5, MDAL_M_datasetGroupCount( m ) );

    // add scalar group
    MDAL_DatasetGroupH g = MDAL_M_addDatasetGroup(
                             m,
                             "scalarGrp",
                             MDAL_DataLocation::DataOnFaces,
                             true,
                             driver,
                             newFile.c_str()
                           );
    ASSERT_NE( g, nullptr );
    MDAL_G_addDataset( g,
                       0.0,
                       valsScalar.data(),
                       nullptr
                     );
    MDAL_G_addDataset( g,
                       1.0,
                       valsScalar.data(),
                       nullptr
                     );
    ASSERT_TRUE( MDAL_G_isInEditMode( g ) );
    MDAL_G_closeEditMode( g );
    ASSERT_EQ( 6, MDAL_M_datasetGroupCount( m ) );
    ASSERT_FALSE( MDAL_G_isInEditMode( g ) );
    ASSERT_EQ( 2, MDAL_G_datasetCount( g ) );

    // add vector group
    MDAL_DatasetGroupH gV = MDAL_M_addDatasetGroup(
                              m,
                              "vectorGrp",
                              MDAL_DataLocation::DataOnFaces,
                              false,
                              driver,
                              newFile.c_str()
                            );
    ASSERT_NE( gV, nullptr );
    MDAL_G_addDataset( gV,
                       0.0,
                       valsVector.data(),
                       nullptr
                     );
    MDAL_G_addDataset( gV,
                       1.0,
                       valsVector.data(),
                       nullptr
                     );
    ASSERT_TRUE( MDAL_G_isInEditMode( gV ) );
    MDAL_G_closeEditMode( gV );
    ASSERT_EQ( 7, MDAL_M_datasetGroupCount( m ) );
    ASSERT_FALSE( MDAL_G_isInEditMode( gV ) );
    ASSERT_EQ( 2, MDAL_G_datasetCount( gV ) );

    MDAL_CloseMesh( m );
  }

  // Ok, now try to load it from the new
  // file and test the
  // values are there
  {
    EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh2d" );
    MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
    ASSERT_NE( m, nullptr );
    ASSERT_EQ( 5, MDAL_M_datasetGroupCount( m ) );
    MDAL_M_LoadDatasets( m, newFile.c_str() );
    MDAL_Status s = MDAL_LastStatus();
    EXPECT_EQ( MDAL_Status::None, s );
    ASSERT_EQ( 7, MDAL_M_datasetGroupCount( m ) );

    // scalar group
    {
      MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 5 );
      ASSERT_NE( g, nullptr );

      const char *name = MDAL_G_name( g );
      EXPECT_EQ( std::string( "scalarGrp" ), std::string( name ) );

      bool scalar = MDAL_G_hasScalarData( g );
      EXPECT_EQ( true, scalar );

      MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
      EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

      ASSERT_EQ( 2, MDAL_G_datasetCount( g ) );
      MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
      ASSERT_NE( ds, nullptr );

      bool valid = MDAL_D_isValid( ds );
      EXPECT_EQ( true, valid );

      EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

      int count = MDAL_D_valueCount( ds );
      ASSERT_EQ( f_count, count );

      double value = getValue( ds, 2 );
      EXPECT_DOUBLE_EQ( 1.1000000238418579, value );
    }

    // vector group
    {
      MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 6 );
      ASSERT_NE( g, nullptr );

      const char *name = MDAL_G_name( g );
      EXPECT_EQ( std::string( "vectorGrp" ), std::string( name ) );

      bool scalar = MDAL_G_hasScalarData( g );
      EXPECT_EQ( false, scalar );

      MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
      EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

      ASSERT_EQ( 2, MDAL_G_datasetCount( g ) );
      MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
      ASSERT_NE( ds, nullptr );

      bool valid = MDAL_D_isValid( ds );
      EXPECT_EQ( true, valid );

      EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

      int count = MDAL_D_valueCount( ds );
      ASSERT_EQ( f_count, count );

      double value = getValueX( ds, 5 );
      EXPECT_DOUBLE_EQ( 2.2000000476837158, value );
    }

    MDAL_CloseMesh( m );
  }
}

TEST( MeshFlo2dTest, WriteBarnHDF5_Append )
{
  std::string pathOrig = test_file( "/flo2d/BarnHDF5/TIMDEP.HDF5" );
  std::string cadtsFile = tmp_file( "/CADPTS.DAT" );
  std::string fplainFile = tmp_file( "/FPLAIN.DAT" );
  std::string appendedFile = tmp_file( "/TIMDEP.HDF5" );

  //prepare
  deleteFile( cadtsFile );
  deleteFile( fplainFile );
  deleteFile( appendedFile );

  copy( test_file( "/flo2d/BarnHDF5/TIMDEP.HDF5" ), appendedFile );
  copy( test_file( "/flo2d/BarnHDF5/CADPTS.DAT" ), cadtsFile );
  copy( test_file( "/flo2d/BarnHDF5/FPLAIN.DAT" ), fplainFile );

  // FLO-2D is only on face datasets
  size_t f_count = 521;
  std::vector<double> valsScalar( f_count );
  std::vector<double> valsVector( 2 * f_count );

  for ( size_t i = 0; i < f_count; ++i )
  {
    double val = static_cast<double>( i );
    valsScalar[i] = val;
    valsVector[2 * i] = val;
    valsVector[2 * i + 1] = 2 * val;
  }

  // Create a new dat file
  {
    EXPECT_EQ( MDAL_MeshNames( pathOrig.c_str() ), "FLO2D:\"" + pathOrig + "\":" + "mesh2d" );
    MDAL_MeshH m = MDAL_LoadMesh( pathOrig.c_str() );
    ASSERT_NE( m, nullptr );
    MDAL_DriverH driver = MDAL_driverFromName( "FLO2D" );
    const char *suffix = MDAL_DR_writeDatasetsSuffix( driver );
    EXPECT_EQ( std::string( "" ), std::string( suffix ) );
    ASSERT_NE( driver, nullptr );
    ASSERT_EQ( 5, MDAL_M_datasetGroupCount( m ) );

    // add scalar group
    MDAL_DatasetGroupH g = MDAL_M_addDatasetGroup(
                             m,
                             "scalarGrp",
                             MDAL_DataLocation::DataOnFaces,
                             true,
                             driver,
                             appendedFile.c_str()
                           );
    ASSERT_NE( g, nullptr );
    MDAL_G_addDataset( g,
                       0.0,
                       valsScalar.data(),
                       nullptr
                     );
    MDAL_G_addDataset( g,
                       1.0,
                       valsScalar.data(),
                       nullptr
                     );
    ASSERT_TRUE( MDAL_G_isInEditMode( g ) );
    MDAL_G_closeEditMode( g );
    ASSERT_EQ( 6, MDAL_M_datasetGroupCount( m ) );
    ASSERT_FALSE( MDAL_G_isInEditMode( g ) );
    ASSERT_EQ( 2, MDAL_G_datasetCount( g ) );

    // add vector group
    MDAL_DatasetGroupH gV = MDAL_M_addDatasetGroup(
                              m,
                              "vectorGrp",
                              MDAL_DataLocation::DataOnFaces,
                              false,
                              driver,
                              appendedFile.c_str()
                            );
    ASSERT_NE( gV, nullptr );
    MDAL_G_addDataset( gV,
                       0.0,
                       valsVector.data(),
                       nullptr
                     );
    MDAL_G_addDataset( gV,
                       1.0,
                       valsVector.data(),
                       nullptr
                     );
    ASSERT_TRUE( MDAL_G_isInEditMode( gV ) );
    MDAL_G_closeEditMode( gV );
    ASSERT_EQ( 7, MDAL_M_datasetGroupCount( m ) );
    ASSERT_FALSE( MDAL_G_isInEditMode( gV ) );
    ASSERT_EQ( 2, MDAL_G_datasetCount( gV ) );

    MDAL_CloseMesh( m );
  }

  // Ok, now try to load it from the new
  // file and test the
  // values are there
  {
    EXPECT_EQ( MDAL_MeshNames( appendedFile.c_str() ), "FLO2D:\"" + appendedFile + "\":" + "mesh2d" );
    MDAL_MeshH m = MDAL_LoadMesh( appendedFile.c_str() );
    ASSERT_NE( m, nullptr );
    MDAL_Status s = MDAL_LastStatus();
    EXPECT_EQ( MDAL_Status::None, s );
    ASSERT_EQ( 7, MDAL_M_datasetGroupCount( m ) );

    // scalar group
    {
      MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 5 );
      ASSERT_NE( g, nullptr );

      const char *name = MDAL_G_name( g );
      EXPECT_EQ( std::string( "scalarGrp" ), std::string( name ) );

      bool scalar = MDAL_G_hasScalarData( g );
      EXPECT_EQ( true, scalar );

      MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
      EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

      ASSERT_EQ( 2, MDAL_G_datasetCount( g ) );
      MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
      ASSERT_NE( ds, nullptr );

      bool valid = MDAL_D_isValid( ds );
      EXPECT_EQ( true, valid );

      EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

      int count = MDAL_D_valueCount( ds );
      ASSERT_EQ( f_count, count );

      double value = getValue( ds, 0 );
      EXPECT_TRUE( std::isnan( value ) );

      value = getValue( ds, 200 );
      EXPECT_DOUBLE_EQ( 200.0, value );

      value = getValue( ds, 500 );
      EXPECT_DOUBLE_EQ( 500.0, value );
    }

    // vector group
    {
      MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 6 );
      ASSERT_NE( g, nullptr );

      const char *name = MDAL_G_name( g );
      EXPECT_EQ( std::string( "vectorGrp" ), std::string( name ) );

      bool scalar = MDAL_G_hasScalarData( g );
      EXPECT_EQ( false, scalar );

      MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
      EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

      ASSERT_EQ( 2, MDAL_G_datasetCount( g ) );
      MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
      ASSERT_NE( ds, nullptr );

      bool valid = MDAL_D_isValid( ds );
      EXPECT_EQ( true, valid );

      EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

      int count = MDAL_D_valueCount( ds );
      ASSERT_EQ( f_count, count );

      double value = getValueX( ds, 0 );
      EXPECT_TRUE( std::isnan( value ) );

      value = getValueX( ds, 200 );
      EXPECT_DOUBLE_EQ( 200.0, value );

      value = getValueX( ds, 500 );
      EXPECT_DOUBLE_EQ( 500.0, value );

      value = getValueY( ds, 0 );
      EXPECT_TRUE( std::isnan( value ) );

      value = getValueY( ds, 200 );
      EXPECT_DOUBLE_EQ( 2 * 200.0, value );

      value = getValueY( ds, 500 );
      EXPECT_DOUBLE_EQ( 2 * 500.0, value );

    }

    MDAL_CloseMesh( m );
  }

  //cleanup
  deleteFile( cadtsFile );
  deleteFile( fplainFile );
}

TEST( MeshFlo2dTest, BarnHDF5 )
{
  std::string path = test_file( "/flo2d/BarnHDF5/BASE.OUT" );
  EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh2d" );
  MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
  EXPECT_NE( m, nullptr );
  MDAL_Status s = MDAL_LastStatus();
  ASSERT_EQ( MDAL_Status::None, s );

  // ///////////
  // Vertices
  // ///////////
  int v_count = MDAL_M_vertexCount( m );
  EXPECT_EQ( v_count, 571 );

  // the vertices are shifted by cell 1/2 size
  // from numbers that are present in CADPTS.DAT
  // file
  std::vector<double> expectedCoords =
  {
    50.0, -50.0, 0.000,
    50.0,  50.0, 0.000,
    -50.0,  50.0, 0.000,
    -50.0, -50.0, 0.000
  };
  EXPECT_EQ( expectedCoords.size(), 4 * 3 );

  std::vector<double> coordinates = getCoordinates( m, 4 );

  EXPECT_TRUE( compareVectors( expectedCoords, coordinates ) );

  // ///////////
  // Faces
  // ///////////
  int f_count = MDAL_M_faceCount( m );
  EXPECT_EQ( 521, f_count );

  // test face 1
  int f_v_count = getFaceVerticesCountAt( m, 1 );
  EXPECT_EQ( 4, f_v_count ); //quad
  int f_v = getFaceVerticesIndexAt( m, 1, 0 );
  EXPECT_EQ( 4, f_v );
  f_v = getFaceVerticesIndexAt( m, 1, 1 );
  EXPECT_EQ( 5, f_v );
  f_v = getFaceVerticesIndexAt( m, 1, 2 );
  EXPECT_EQ( 1, f_v );
  f_v = getFaceVerticesIndexAt( m, 1, 3 );
  EXPECT_EQ( 0, f_v );

  // ///////////
  // Bed elevation dataset
  // ///////////
  ASSERT_EQ( 5, MDAL_M_datasetGroupCount( m ) );

  MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 0 );
  ASSERT_NE( g, nullptr );

  int meta_count = MDAL_G_metadataCount( g );
  ASSERT_EQ( 1, meta_count );

  const char *name = MDAL_G_name( g );
  EXPECT_EQ( std::string( "Bed Elevation" ), std::string( name ) );

  bool scalar = MDAL_G_hasScalarData( g );
  EXPECT_EQ( true, scalar );

  MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
  EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

  ASSERT_EQ( 1, MDAL_G_datasetCount( g ) );
  MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
  ASSERT_NE( ds, nullptr );

  bool valid = MDAL_D_isValid( ds );
  EXPECT_EQ( true, valid );

  EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

  int count = MDAL_D_valueCount( ds );
  ASSERT_EQ( 521, count );

  double value = getValue( ds, 0 );
  EXPECT_DOUBLE_EQ( 4261.2799999999997, value );
  value = getValue( ds, 1 );
  EXPECT_DOUBLE_EQ( 4262.8800000000001, value );
  value = getValue( ds, 2 );
  EXPECT_DOUBLE_EQ( 4262.8299999999999, value );
  value = getValue( ds, 3 );
  EXPECT_DOUBLE_EQ( 4262.7700000000004, value );

  // ///////////
  // Scalar Dataset
  // ///////////
  g = MDAL_M_datasetGroup( m, 1 );
  ASSERT_NE( g, nullptr );

  meta_count = MDAL_G_metadataCount( g );
  ASSERT_EQ( 1, meta_count );

  name = MDAL_G_name( g );
  EXPECT_EQ( std::string( "FLOW DEPTH" ), std::string( name ) );

  scalar = MDAL_G_hasScalarData( g );
  EXPECT_EQ( true, scalar );

  dataLocation = MDAL_G_dataLocation( g );
  EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

  ASSERT_EQ( 20, MDAL_G_datasetCount( g ) );
  ds = MDAL_G_dataset( g, 0 );
  ASSERT_NE( ds, nullptr );

  double time = MDAL_D_time( ds );
  EXPECT_TRUE( compareDurationInHours( 0.10124753560882101, time ) );

  EXPECT_FALSE( hasReferenceTime( g ) );

  valid = MDAL_D_isValid( ds );
  EXPECT_EQ( true, valid );

  EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

  count = MDAL_D_valueCount( ds );
  ASSERT_EQ( 521, count );

  value = getValue( ds, 1 );
  EXPECT_DOUBLE_EQ( 4262.8798828125, value );

  double min, max;
  MDAL_D_minimumMaximum( ds, &min, &max );
  EXPECT_DOUBLE_EQ( 4259.18017578125, min );
  EXPECT_DOUBLE_EQ( 4520, max );

  MDAL_G_minimumMaximum( g, &min, &max );
  EXPECT_DOUBLE_EQ( 4259.18017578125, min );
  EXPECT_DOUBLE_EQ( 4520, max );

  // ///////////
  // Vector Dataset
  // ///////////
  g = MDAL_M_datasetGroup( m, 3 );
  ASSERT_NE( g, nullptr );

  meta_count = MDAL_G_metadataCount( g );
  ASSERT_EQ( 1, meta_count );

  name = MDAL_G_name( g );
  EXPECT_EQ( std::string( "Velocity" ), std::string( name ) );

  scalar = MDAL_G_hasScalarData( g );
  EXPECT_EQ( false, scalar );

  dataLocation = MDAL_G_dataLocation( g );
  EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

  ASSERT_EQ( 20, MDAL_G_datasetCount( g ) );
  ds = MDAL_G_dataset( g, 17 );
  ASSERT_NE( ds, nullptr );

  valid = MDAL_D_isValid( ds );
  EXPECT_EQ( true, valid );

  EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

  count = MDAL_D_valueCount( ds );
  ASSERT_EQ( 521, count );

  value = getValueX( ds, 234 );
  EXPECT_DOUBLE_EQ( 0.27071857452392578, value );

  value = getValueY( ds, 234 );
  EXPECT_DOUBLE_EQ( -0.62059682607650757, value );

  MDAL_D_minimumMaximum( ds, &min, &max );
  EXPECT_DOUBLE_EQ( 0.1241119660936652, min );
  EXPECT_DOUBLE_EQ( 2.847882132344469, max );

  MDAL_CloseMesh( m );
}

TEST( MeshFlo2dTest, basic )
{
  std::vector<std::string> files;
  files.push_back( "basic" );
  files.push_back( "basic_with_dos_eol" );
  for ( const std::string &file : files )
  {
    std::string path = test_file( "/flo2d/" + file + "/BASE.OUT" );
    EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh2d" );
    MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
    ASSERT_NE( m, nullptr );
    MDAL_Status s = MDAL_LastStatus();
    EXPECT_EQ( MDAL_Status::None, s );

    // ///////////
    // Vertices
    // ///////////
    int v_count = MDAL_M_vertexCount( m );
    EXPECT_EQ( v_count, 16 );

    std::vector<double> expectedCoords =
    {
      2.09, 2.50, 0.00,
      2.09, 3.50, 0.00,
      1.09, 3.50, 0.00,
    };
    EXPECT_EQ( expectedCoords.size(), 3 * 3 );

    std::vector<double> coordinates = getCoordinates( m, 3 );

    EXPECT_TRUE( compareVectors( expectedCoords, coordinates ) );

    // ///////////
    // Faces
    // ///////////
    int f_count = MDAL_M_faceCount( m );
    EXPECT_EQ( 9, f_count );

    // test face 1
    int f_v_count = getFaceVerticesCountAt( m, 1 );
    EXPECT_EQ( 4, f_v_count ); //quad
    int f_v = getFaceVerticesIndexAt( m, 1, 0 );
    EXPECT_EQ( 4, f_v );
    f_v = getFaceVerticesIndexAt( m, 1, 1 );
    EXPECT_EQ( 5, f_v );
    f_v = getFaceVerticesIndexAt( m, 1, 2 );
    EXPECT_EQ( 1, f_v );
    f_v = getFaceVerticesIndexAt( m, 1, 3 );
    EXPECT_EQ( 0, f_v );

    // ///////////
    // Bed elevation dataset
    // ///////////
    ASSERT_EQ( 7, MDAL_M_datasetGroupCount( m ) );

    MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 0 );
    ASSERT_NE( g, nullptr );

    int meta_count = MDAL_G_metadataCount( g );
    ASSERT_EQ( 1, meta_count );

    const char *name = MDAL_G_name( g );
    EXPECT_EQ( std::string( "Bed Elevation" ), std::string( name ) );

    bool scalar = MDAL_G_hasScalarData( g );
    EXPECT_EQ( true, scalar );

    MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
    EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

    ASSERT_EQ( 1, MDAL_G_datasetCount( g ) );
    MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
    ASSERT_NE( ds, nullptr );

    bool valid = MDAL_D_isValid( ds );
    EXPECT_EQ( true, valid );

    EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

    int count = MDAL_D_valueCount( ds );
    ASSERT_EQ( 9, count );

    double value = getValue( ds, 0 );
    EXPECT_DOUBLE_EQ( 1.48, value );

    // ///////////
    // Scalar Dataset
    // ///////////
    g = MDAL_M_datasetGroup( m, 1 );
    ASSERT_NE( g, nullptr );

    meta_count = MDAL_G_metadataCount( g );
    ASSERT_EQ( 1, meta_count );

    name = MDAL_G_name( g );
    EXPECT_EQ( std::string( "Depth" ), std::string( name ) );

    scalar = MDAL_G_hasScalarData( g );
    EXPECT_EQ( true, scalar );

    dataLocation = MDAL_G_dataLocation( g );
    EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

    ASSERT_EQ( 3, MDAL_G_datasetCount( g ) );
    ds = MDAL_G_dataset( g, 0 );
    ASSERT_NE( ds, nullptr );

    valid = MDAL_D_isValid( ds );
    EXPECT_EQ( true, valid );

    EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

    count = MDAL_D_valueCount( ds );
    ASSERT_EQ( 9, count );

    value = getValue( ds, 1 );
    EXPECT_DOUBLE_EQ( 1, value );

    double min, max;
    MDAL_D_minimumMaximum( ds, &min, &max );
    EXPECT_DOUBLE_EQ( 1, min );
    EXPECT_DOUBLE_EQ( 1, max );

    MDAL_G_minimumMaximum( g, &min, &max );
    EXPECT_DOUBLE_EQ( 1, min );
    EXPECT_DOUBLE_EQ( 3, max );

    double time = MDAL_D_time( ds );
    EXPECT_TRUE( compareDurationInHours( 0.5, time ) );

    EXPECT_FALSE( hasReferenceTime( g ) );

    // ///////////
    // Max Depth
    // ///////////
    g = MDAL_M_datasetGroup( m, 4 );
    ASSERT_NE( g, nullptr );

    meta_count = MDAL_G_metadataCount( g );
    ASSERT_EQ( 1, meta_count );

    name = MDAL_G_name( g );
    EXPECT_EQ( std::string( "Depth/Maximums" ), std::string( name ) );

    scalar = MDAL_G_hasScalarData( g );
    EXPECT_EQ( true, scalar );

    dataLocation = MDAL_G_dataLocation( g );
    EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

    ASSERT_EQ( 1, MDAL_G_datasetCount( g ) );
    ds = MDAL_G_dataset( g, 0 );
    ASSERT_NE( ds, nullptr );

    valid = MDAL_D_isValid( ds );
    EXPECT_EQ( true, valid );

    EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

    count = MDAL_D_valueCount( ds );
    ASSERT_EQ( 9, count );

    value = getValue( ds, 1 );
    EXPECT_DOUBLE_EQ( 2, value );

    MDAL_D_minimumMaximum( ds, &min, &max );
    EXPECT_DOUBLE_EQ( 2, min );
    EXPECT_DOUBLE_EQ( 4, max );

    MDAL_G_minimumMaximum( g, &min, &max );
    EXPECT_DOUBLE_EQ( 2, min );
    EXPECT_DOUBLE_EQ( 4, max );

    MDAL_CloseMesh( m );
  }
}

TEST( MeshFlo2dTest, basic_required_files_only )
{
  std::string path = test_file( "/flo2d/basic_required_files_only/BASE.OUT" );
  EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh2d" );
  MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
  ASSERT_NE( m, nullptr );
  MDAL_Status s = MDAL_LastStatus();
  EXPECT_EQ( MDAL_Status::None, s );

  const char *projection = MDAL_M_projection( m );
  EXPECT_EQ( std::string( "" ), std::string( projection ) );

  // ///////////
  // Vertices
  // ///////////
  int v_count = MDAL_M_vertexCount( m );
  EXPECT_EQ( v_count, 16 );

  // ///////////
  // Faces
  // ///////////
  int f_count = MDAL_M_faceCount( m );
  EXPECT_EQ( 9, f_count );

  // ///////////
  // Bed elevation dataset
  // ///////////
  ASSERT_EQ( 1, MDAL_M_datasetGroupCount( m ) );

  MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 0 );
  ASSERT_NE( g, nullptr );

  int meta_count = MDAL_G_metadataCount( g );
  ASSERT_EQ( 1, meta_count );

  const char *name = MDAL_G_name( g );
  EXPECT_EQ( std::string( "Bed Elevation" ), std::string( name ) );

  bool scalar = MDAL_G_hasScalarData( g );
  EXPECT_EQ( true, scalar );

  MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
  EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

  ASSERT_EQ( 1, MDAL_G_datasetCount( g ) );
  MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
  ASSERT_NE( ds, nullptr );

  bool valid = MDAL_D_isValid( ds );
  EXPECT_EQ( true, valid );

  EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

  int count = MDAL_D_valueCount( ds );
  ASSERT_EQ( 9, count );

  double value = getValue( ds, 0 );
  EXPECT_DOUBLE_EQ( 1.48, value );

  EXPECT_FALSE( hasReferenceTime( g ) );

  MDAL_CloseMesh( m );
}

TEST( MeshFlo2dTest, pro_16_02_14 )
{
  std::string path = test_file( "/flo2d/pro_16_02_14/BASE.OUT" );
  EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh2d" );
  MDAL_MeshH m = MDAL_LoadMesh( path.c_str() );
  ASSERT_NE( m, nullptr );
  MDAL_Status s = MDAL_LastStatus();
  EXPECT_EQ( MDAL_Status::None, s );

  // ///////////
  // Vertices
  // ///////////
  int v_count = MDAL_M_vertexCount( m );
  EXPECT_EQ( v_count, 5443 );

  // ///////////
  // Faces
  // ///////////
  int f_count = MDAL_M_faceCount( m );
  EXPECT_EQ( 5101, f_count );

  // test face 1
  int f_v_count = getFaceVerticesCountAt( m, 1 );
  EXPECT_EQ( 4, f_v_count ); //quad

  // ///////////
  // Bed elevation dataset
  // ///////////
  ASSERT_EQ( 7, MDAL_M_datasetGroupCount( m ) );

  MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 0 );
  ASSERT_NE( g, nullptr );

  int meta_count = MDAL_G_metadataCount( g );
  ASSERT_EQ( 1, meta_count );

  const char *name = MDAL_G_name( g );
  EXPECT_EQ( std::string( "Bed Elevation" ), std::string( name ) );

  bool scalar = MDAL_G_hasScalarData( g );
  EXPECT_EQ( true, scalar );

  MDAL_DataLocation dataLocation = MDAL_G_dataLocation( g );
  EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

  ASSERT_EQ( 1, MDAL_G_datasetCount( g ) );
  MDAL_DatasetH ds = MDAL_G_dataset( g, 0 );
  ASSERT_NE( ds, nullptr );

  bool valid = MDAL_D_isValid( ds );
  EXPECT_EQ( true, valid );

  EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

  int count = MDAL_D_valueCount( ds );
  ASSERT_EQ( 5101, count );

  double value = getValue( ds, 3 );
  EXPECT_DOUBLE_EQ( 4904.2299999999996, value );

  // ///////////
  // Scalar Dataset
  // ///////////
  g = MDAL_M_datasetGroup( m, 1 );
  ASSERT_NE( g, nullptr );

  meta_count = MDAL_G_metadataCount( g );
  ASSERT_EQ( 1, meta_count );

  name = MDAL_G_name( g );
  EXPECT_EQ( std::string( "Depth" ), std::string( name ) );

  scalar = MDAL_G_hasScalarData( g );
  EXPECT_EQ( true, scalar );

  dataLocation = MDAL_G_dataLocation( g );
  EXPECT_EQ( dataLocation, MDAL_DataLocation::DataOnFaces );

  ASSERT_EQ( 4, MDAL_G_datasetCount( g ) );
  ds = MDAL_G_dataset( g, 2 );
  ASSERT_NE( ds, nullptr );

  double time = MDAL_D_time( ds );
  EXPECT_TRUE( compareDurationInHours( 150.0, time ) );

  EXPECT_FALSE( hasReferenceTime( g ) );

  valid = MDAL_D_isValid( ds );
  EXPECT_EQ( true, valid );

  EXPECT_FALSE( MDAL_D_hasActiveFlagCapability( ds ) );

  count = MDAL_D_valueCount( ds );
  ASSERT_EQ( 5101, count );

  value = getValue( ds, 1 );
  EXPECT_DOUBLE_EQ( 0.098000000000000004, value );


  MDAL_CloseMesh( m );
}

TEST( MeshFlo2dTest, mesh1D )
{
  std::string path = test_file( "/flo2d/channel/CADPTS.DAT" );
  EXPECT_EQ( MDAL_MeshNames( path.c_str() ), "FLO2D:\"" + path + "\":" + "mesh1d" );
  std::string uri1d = "FLO2D:\"" + path + "\":" + "mesh1d";

  MDAL_MeshH m = MDAL_LoadMesh( uri1d.c_str() );
  ASSERT_NE( m, nullptr );
  MDAL_Status s = MDAL_LastStatus();
  EXPECT_EQ( MDAL_Status::None, s );

  // ///////////
  // Vertices
  // ///////////
  int v_count = MDAL_M_vertexCount( m );
  EXPECT_EQ( v_count, 66 );
  EXPECT_TRUE( MDAL::equals( getVertexXCoordinatesAt( m, 10 ), 1361905 ) );
  EXPECT_TRUE( MDAL::equals( getVertexYCoordinatesAt( m, 10 ), 73194.93 ) );
  EXPECT_TRUE( MDAL::equals( getVertexXCoordinatesAt( m, 20 ), 1361705 ) );
  EXPECT_TRUE( MDAL::equals( getVertexYCoordinatesAt( m, 20 ), 73234.93 ) );

  // ///////////
  // Edges
  // ///////////
  int e_count = MDAL_M_edgeCount( m );
  EXPECT_EQ( 65, e_count );
  std::vector<int> startIndexes;
  std::vector<int> endIndexes;
  getEdgeVertexIndices( m, e_count, startIndexes, endIndexes );
  EXPECT_EQ( startIndexes[10], 10 );
  EXPECT_EQ( endIndexes[10], 11 );
  EXPECT_EQ( startIndexes[20], 20 );
  EXPECT_EQ( endIndexes[20], 21 );

  // ///////////
  // Datasets
  // ///////////
  ASSERT_EQ( 13, MDAL_M_datasetGroupCount( m ) );
  MDAL_DatasetGroupH g = MDAL_M_datasetGroup( m, 11 );
  ASSERT_NE( g, nullptr );
  ASSERT_EQ( "BED SHEAR STRESS", std::string( MDAL_G_name( g ) ) );
  ASSERT_EQ( DataOnVertices, MDAL_G_dataLocation( g ) );
  ASSERT_EQ( 50, MDAL_G_datasetCount( g ) );
  MDAL_DatasetH ds = MDAL_G_dataset( g, 2 );
  ASSERT_NE( ds, nullptr );
  ASSERT_TRUE( MDAL::equals( 0.24264, getValue( ds,  5 ) ) );
  double min, max;
  MDAL_G_minimumMaximum( g, &min, &max );
  ASSERT_EQ( min, 0.0 );
  ASSERT_EQ( max, 1.206 );

  g = MDAL_M_datasetGroup( m, 10 );
  ASSERT_NE( g, nullptr );
  ASSERT_EQ( "ENERGY SLOPE", std::string( MDAL_G_name( g ) ) );
  ASSERT_EQ( DataOnVertices, MDAL_G_dataLocation( g ) );
  ASSERT_EQ( 50, MDAL_G_datasetCount( g ) );
  ds = MDAL_G_dataset( g, 2 );
  ASSERT_NE( ds, nullptr );
  ASSERT_TRUE( MDAL::equals( 0.012488, getValue( ds,  5 ) ) );
  MDAL_G_minimumMaximum( g, &min, &max );
  ASSERT_EQ( min, 0.0 );
  ASSERT_EQ( max, 0.023452 );

  MDAL_CloseMesh( m );
}


int main( int argc, char **argv )
{
  testing::InitGoogleTest( &argc, argv );
  init_test();
  int ret =  RUN_ALL_TESTS();
  finalize_test();
  return ret;
}

